/**
 *    Copyright 2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.dianwoba.core.mybatis;

import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;

import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

import com.dianwoba.core.redis.connection.ShardedJedisSentinelPool;
import com.dianwoba.core.spring.ContextHolder;

import redis.clients.jedis.ShardedJedis;

/**
 * @author Zhu
 * @date 2016年6月1日 下午2:12:30
 * @description
 */
public final class RedisCache implements Cache {

	private String id;

	private static JdkSerializationRedisSerializer serializer = new JdkSerializationRedisSerializer();
	
	private static ShardedJedisSentinelPool pool;

	private ShardedJedisSentinelPool getShardedJedisSentinelPool() {
		if (pool == null) {
			pool = (ShardedJedisSentinelPool) ContextHolder.getBean("shardedJedisConnectionPool");
		}
		return pool;
	}

	public RedisCache(final String id) {
		if (id == null) {
			throw new IllegalArgumentException("Cache instances require an ID");
		}
		this.id = id;
	}

	private Object execute(RedisCallback callback) {
		ShardedJedis jedis = getShardedJedisSentinelPool().getResource();
		try {
			return callback.doWithRedis(jedis);
		} finally {
			getShardedJedisSentinelPool().returnResource(jedis);
		}
	}

	@Override
	public String getId() {
		return this.id;
	}

	@Override
	public int getSize() {
		return (Integer) execute(new RedisCallback() {
			@Override
			public Object doWithRedis(ShardedJedis jedis) {
				Map<byte[], byte[]> result = jedis.hgetAll(id.toString().getBytes());
				return result.size();
			}
		});
	}

	@Override
	public void putObject(final Object key, final Object value) {
		execute(new RedisCallback() {
			@Override
			public Object doWithRedis(ShardedJedis jedis) {
				jedis.hset(id.toString().getBytes(), key.toString().getBytes(), serializer.serialize(value));
				return null;
			}
		});
	}

	@Override
	public Object getObject(final Object key) {
		return execute(new RedisCallback() {
			@Override
			public Object doWithRedis(ShardedJedis jedis) {
				return serializer.deserialize(jedis.hget(id.toString().getBytes(), key.toString().getBytes()));
			}
		});
	}

	@Override
	public Object removeObject(final Object key) {
		return execute(new RedisCallback() {
			@Override
			public Object doWithRedis(ShardedJedis jedis) {
				return jedis.hdel(id.toString(), key.toString());
			}
		});
	}

	@Override
	public void clear() {
		execute(new RedisCallback() {
			@Override
			public Object doWithRedis(ShardedJedis jedis) {
				jedis.del(id.toString());
				return null;
			}
		});

	}

	@Override
	public ReadWriteLock getReadWriteLock() {
		return null;
	}

	@Override
	public String toString() {
		return "Redis {" + id + "}";
	}

}
